package com.demo.security.impl;

import java.util.ArrayList;
import java.util.Collection;

import com.demo.security.access.model.SecurityRole;
import com.demo.security.access.model.SecurityUser;
import com.demo.security.service.UserAccessService;
import com.demo.security.web.exception.SiteAccessException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.Assert;

/**
 * 用户详细信息服务支持<br>
 * 将用户名进行出去,取得用户&角色信息
 * 封装UserDetails对象
 * SpringSecurity进行处理
 * 
 * @author ryuu.kk
 *         at 2013-06-04 新增方法 createUserDetails.
 *
 */
public abstract class UserDetailsServiceSupport implements UserDetailsService, InitializingBean {
	
	/**
	 * 日志
	 */
	protected static final Log LOG = LogFactory.getLog(UserDetailsServiceSupport.class);
	
	/**
	 * 用户访问服务
	 */
	private UserAccessService userService;
	
	/**
	 * 用户模型对象
	 */
	private SecurityUser user;

	/**
	 * 使用Dao验证用户账号/密码是否对应
	 * @param username 用户账户名
	 * @throws DataAccessException 数据访问异常
	 * @throws UsernameNotFoundException 不存在该用户账户异常
	 */
	@Override
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException {
		UserDetails userDetail = null;
		try {
			user = userService.find(username);
			if (user == null) throw new UsernameNotFoundException(username);
		}  catch (DataAccessException e) {
			throw e;
		}
		/* **************************************************************
		 * 更新为使用UserDetailsImpl的构造方式注入SecurityUser对象和Collection<GrantedAuthority>
		 * at 2012-11-19 
		userDetail = new UserDetailsImpl<SecurityUser>();
		userDetail.setPassword(user.getPassword());
		userDetail.setUsername(user.getUserName());
		userDetail.setUser(user);
		// userDetail.setEnabled("T".equals(user.getEnabled()));
		// 修改用户不可用bug
		userDetail.setEnabled(user.getEnabled());
		userDetail.setAuthorities(this.getGrantedAuthority(user));
		***************************************************************** */
		// 新的UserDetailsImpl方法
		Collection<GrantedAuthority> grantedAuths = this.getGrantedAuthority(user);
		// 生成UserDetails对象
		userDetail = createUserDetails(user, grantedAuths);
		
		if (LOG.isInfoEnabled()) {
			LOG.info("user login success! userId:" + user.getId() + " userName:" + user.getUserName());
		}
		return userDetail;
	}
	
	/**
	 * 取得权限用户信息内容
	 * @param user 权限列表
	 * @return Collection<GrantedAuthority> 角色列表
	 */
	protected Collection<GrantedAuthority> getGrantedAuthority(SecurityUser user) {
		Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		
		//authorities.add(new SimpleGrantedAuthority("ROLE_ANONYMOUS"));
		Collection<SecurityRole> roleList = getRoles(user);
		for (SecurityRole role : roleList) {
			authorities.add(new SimpleGrantedAuthority(role.getRoleName()));
		}
		/* **************************************************************
		 * 新增对内置用户的权限处理
		 * at 2013-01-25
		 **************************************************************** */
		// 对内置特殊用户进行处理
		rootGrantedAuthority(user, authorities);
		
		return authorities;
	}

	/**
	 * 增加创建UserDetails方法
	 * <br/>创建新的登录用户信息模型
	 * @return UserDetails
	 */
	protected UserDetails createUserDetails(SecurityUser user, Collection<GrantedAuthority> grantedAuths) {
		return new UserDetailsWrapper<SecurityUser, Object>(user, user, grantedAuths);
	}
	
	/**
	 * 对内置账户进行判断
	 * @param user SecurityUser
	 * @param authorities Collection<GrantedAuthority>
	 * 
	 */
	protected void rootGrantedAuthority(SecurityUser user, Collection<GrantedAuthority> authorities) {
		if (user.getUserName().equals("root")) {
			// 内置超级用户
			SimpleGrantedAuthority rootAuthority = new SimpleGrantedAuthority("ROLE_ROOT");
			authorities.add(rootAuthority);
		}
	}
	
	/**
	 * 继承类初始化
	 */
	protected abstract void initInvocation();
	
	/**
	 * 取得用户所对应的角色列表
	 * 该用户将在不同站点有不同的角色，根据访问的站点，
	 * 将站点Site信息取得用户所以应站点的角色。
	 * @param user 用户模型信息
	 * @return 角色列表
	 * @throws SiteAccessException 站点访问异常
	 * @throws DataAccessException 数据访问异常
	 */
	public abstract <T extends SecurityRole> Collection<T> getRoles(SecurityUser user) throws SiteAccessException, DataAccessException;
	
	/**
	 * 初始化操作
	 */
	public void afterPropertiesSet() throws Exception {
		Assert.notNull(userService, "UserService can not null.");
		//super
		initInvocation();
	}
	
	public void setUserAccessService(UserAccessService userService) {
		this.userService = userService;
	}
}